package servlet;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
//创建这棵搜索数的目的主要是为了实现web.xml中ServletMapping的通配符问题，如果不考虑通配符的存在，其实用一个HashMap就可以了
public class ServletMappingTree {
	private TreeNode root;
	private Parser parser= new Parser();
	public ServletMappingTree(){
		//整棵搜索树的树根，其子结点为各个项目的根结点
		this.root = new TreeNode();
		root.setPath("/");
		root.setServletClass(null);
		
	}


	//构建搜索树，这个搜索树更像是一个文件系统的结构，按照文件夹的方式组织
	public void buildTree(File[] projects) {
		for(File project : projects){
			TreeNode projectRoot = new TreeNode();
			String fullpath = project.getPath();
			projectRoot.setPath(fullpath.substring(fullpath.lastIndexOf("\\")+1));
			//将项目根结点加到树根上
			root.getList().add(projectRoot);
			//使用解析器获取web.xml文件中所有Servlet名称和访问路径的偶对
			List<Pair> pairs = parser.xmlParser(project.getPath());
			//将这些偶对按照访问路径的层级进行构建
			for(Pair pair : pairs){
				
				TreeNode current = projectRoot;
				String pp = pair.getUrlPattern().substring(1);
				//该tokens表示的是该结点的url路径中包含的各个文件夹名称，即夹在url中的‘/’之间的部分，结点拥有的token数目即为该结点在树中的深度
				String[] tokens;
				
				if(pp.contains("/")){
					tokens = pair.getUrlPattern().substring(1).split("/");
				}
				else{
					tokens = new String[1];
					tokens[0] = pp;
				}
				for(int i=0;i<tokens.length;i++){
					//按照文件夹的顺序在搜索树中一层一层的查找是否存在各级文件夹的结点，如果有则继续向下深入，若没有则先新建该结点，再向下深入
					TreeNode result = find(current,tokens[i]);
					if(result!=null){
						current = result;
					}
					else{
						TreeNode node = new TreeNode();
						node.setPath(tokens[i]);
						current.getList().add(node);
						//如果已到最后一级，则新建叶子结点，该节点即为Servlet的结点
						if(i==tokens.length-1){
							node.setServletClass(pair.getServletClass());
						}
						current = node;
					}
				}
			}
		}
	}
	private String search(Stack<String> url,TreeNode node){
		//从栈中弹出当前需要查找的结点的路径，在当前结点的子节点中查找
		TreeNode n = find(node,url.pop());
		//如果找到了
		if(n!=null){
			//已到最后一级，即找到了Servlet，则返回Servlet的路径
			if(url.size()==0){
				return n.getServletClass();
			}
			//如果没到最后一级，则递归继续查找
			else{
				return search(url,n);
			}
		}
		//如果在查找的过程中，某一个token（或者说某一级路径）没找到
		else{
			//如果当前查找的是最后一级，即已到Servlet，而且当前路径下存在通配符*，则使用通配符对应的地址返回（也就是说没有找到完整匹配的Servlet路径，但是存在满足条件的通配符的映射）
			if(url.size()==0){
				TreeNode n1 = find(node,"*");
				if(n1!=null){
					return n1.getServletClass();
				}
				else{
					return null;
				}
			}
			else{
				return null;
			}

			
		}
	}
	//按照给定的请求路径找到对应的Servlet的实际路径
	public String search(String path){
		//解析请求路径为一个个token
		Stack<String> url = new Stack<String>();
		path = path.substring(1);
		String[] tokens = path.split("/");
		//将搜索的路径逐级压栈，顶级路径在栈顶
		for(int i=tokens.length-1;i>=0;i--){
			url.push(tokens[i]);
		}
		//调用实际的搜索树搜索方法
		return search(url,root);
	}
	
	
	
	//在当前结点cur的子节点中查找，是否存在对应路径为path的子节点
	private TreeNode find(TreeNode cur, String path){
		for(TreeNode child : cur.getList()){
			if(child.getPath().equals(path)){
				return child;
			}
		}
		return null;
		
		
	}

}
